﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Windows;
using System.Windows.Media;

// This source code obtained from CodeProject and 
// the URL is http://www.codeproject.com/KB/silverlight/TextOnAPathSilverlight.aspx?msg=2872095.
namespace Xceed.Silverlight.Utils
{
  internal class MatrixHelper
  {
    public MatrixHelper()
    {
      m_value = Matrix.Identity;
    }

    public Matrix Value
    {
      get
      {
        return m_value;
      }
      set
      {
        m_value = value;
      }
    }

    public MatrixHelper( Matrix Input )
    {
      m_value = Input;
    }

    public static MatrixHelper operator *( MatrixHelper matrix1, MatrixHelper matrix2 )
    {
      MatrixHelper result = new MatrixHelper();

      result.m_value.M11 = ( matrix1.Value.M11 * matrix2.Value.M11 ) + ( matrix1.Value.M12 * matrix2.Value.M21 );
      result.m_value.M12 = ( matrix1.Value.M11 * matrix2.Value.M12 ) + ( matrix1.Value.M12 * matrix2.Value.M22 );
      result.m_value.M21 = ( matrix1.Value.M21 * matrix2.Value.M11 ) + ( matrix1.Value.M22 * matrix2.Value.M21 );
      result.m_value.M22 = ( matrix1.Value.M21 * matrix2.Value.M12 ) + ( matrix1.Value.M22 * matrix2.Value.M22 );
      result.m_value.OffsetX = ( matrix1.Value.OffsetX * matrix2.Value.M11 ) + ( matrix1.Value.OffsetY * matrix2.Value.M21 ) + matrix2.Value.OffsetX;
      result.m_value.OffsetY = ( matrix1.Value.OffsetX * matrix2.Value.M12 ) + ( matrix1.Value.OffsetY * matrix2.Value.M22 ) + matrix2.Value.OffsetY;

      return ( result );
    }

    public static MatrixHelper Multiply( MatrixHelper Matrix1, MatrixHelper Matrix2 )
    {
      return ( Matrix1 * Matrix2 );
    }

    public Point Transform( Point Point )
    {
      Point result = new Point();

      result.X = ( m_value.M11 * Point.X ) + ( m_value.M12 * Point.Y );
      result.Y = ( m_value.M21 * Point.X ) + ( m_value.M22 * Point.Y );

      return ( result );
    }

    public void Rotate( double Angle )
    {
      double angleRadians = Angle * Math.PI / 180.0;

      MatrixHelper rotationMatrix = new MatrixHelper();
      rotationMatrix.m_value.M11 = Math.Cos( angleRadians );
      rotationMatrix.m_value.M12 = Math.Sin( angleRadians );
      rotationMatrix.m_value.M21 = -rotationMatrix.Value.M12;
      rotationMatrix.m_value.M22 = rotationMatrix.Value.M11;

      MatrixHelper result = this * rotationMatrix;
      m_value.M11 = result.Value.M11;
      m_value.M12 = result.Value.M12;
      m_value.M21 = result.Value.M21;
      m_value.M22 = result.Value.M22;
      m_value.OffsetX = result.Value.OffsetX;
      m_value.OffsetY = result.Value.OffsetY;
    }

    public void Scale( double XScale, double YScale )
    {
      MatrixHelper scaleMatrix = new MatrixHelper();
      scaleMatrix.m_value.M11 = XScale;
      scaleMatrix.m_value.M12 = 0;
      scaleMatrix.m_value.M21 = 0;
      scaleMatrix.m_value.M22 = YScale;

      MatrixHelper result = this * scaleMatrix;
      m_value.M11 = result.Value.M11;
      m_value.M12 = result.Value.M12;
      m_value.M21 = result.Value.M21;
      m_value.M22 = result.Value.M22;
      m_value.OffsetX = result.Value.OffsetX;
      m_value.OffsetY = result.Value.OffsetY;
    }

    public bool HasInverse
    {
      get
      {
        if( this.Determinant == 0 )
          return false;

        return true;
      }
    }

    public void Invert()
    {
      double determinant = this.Determinant;
      if( determinant == 0 )
        throw new System.InvalidOperationException( "Matrix can not be inverted, determinant is zero" );

      double M11 = m_value.M22 / determinant;
      double M12 = -m_value.M12 / determinant;
      double M21 = -m_value.M21 / determinant;
      double M22 = m_value.M11 / determinant;
      double xOffset = ( ( m_value.OffsetY * m_value.M21 ) - ( m_value.OffsetX * m_value.M22 ) ) / determinant;
      double yOffset = ( ( m_value.OffsetX * m_value.M12 ) - ( m_value.OffsetY * m_value.M11 ) ) / determinant;

      m_value.M11 = M11;
      m_value.M12 = M12;
      m_value.M21 = M21;
      m_value.M22 = M22;
      m_value.OffsetX = xOffset;
      m_value.OffsetY = yOffset;
    }

    public double Determinant
    {
      get
      {
        return ( m_value.M11 * m_value.M22 ) - ( m_value.M12 * m_value.M21 );
      }
    }

    #region Private Fields

    private Matrix m_value;

    #endregion
  }
}
